home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / db / esm-3.1 / esm-3 / usr / local / sm / src / serverlib / recover / analyzeCheckpoint.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-05  |  10.1 KB  |  376 lines

  1. /*
  2.  *   $RCSfile: analyzeCheckpoint.c,v $  
  3.  *   $Revision: 1.1.1.1 $  
  4.  *   $Date: 1996/05/04 21:55:55 $      
  5.  */ 
  6. /**********************************************************************
  7. * EXODUS Database Toolkit Software
  8. * Copyright (c) 1991 Computer Sciences Department, University of
  9. *                    Wisconsin -- Madison
  10. * All Rights Reserved.
  11. *
  12. * Permission to use, copy, modify and distribute this software and its
  13. * documentation is hereby granted, provided that both the copyright
  14. * notice and this permission notice appear in all copies of the
  15. * software, derivative works or modified versions, and any portions
  16. * thereof, and that both notices appear in supporting documentation.
  17. *
  18. * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
  19. * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.  
  20. * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  21. * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  22. *
  23. * The EXODUS Project Group requests users of this software to return 
  24. * any improvements or extensions that they make to:
  25. *
  26. *   EXODUS Project Group 
  27. *     c/o David J. DeWitt and Michael J. Carey
  28. *   Computer Sciences Department
  29. *   University of Wisconsin -- Madison
  30. *   Madison, WI 53706
  31. *
  32. *     or exodus@cs.wisc.edu
  33. *
  34. * In addition, the EXODUS Project Group requests that users grant the 
  35. * Computer Sciences Department rights to redistribute these changes.
  36. **********************************************************************/
  37.  
  38. #include "sysdefs.h"
  39. #include "ess.h"
  40. #include "checking.h"
  41. #include "trace.h"
  42. #include "error.h"
  43. #include "list.h"
  44. #include "pool.h"
  45. #include "tid.h"
  46. #include "io.h"
  47. #include "lock.h"
  48. #include "object.h"
  49. #include "msgdefs.h"
  50. #include "thread.h"
  51. #include "semaphore.h"
  52. #include "latch.h"
  53. #include "link.h"
  54. #include "lsn.h"
  55. #include "bf.h"
  56. #include "volume.h"
  57. #include "openlog.h"
  58. #include "trans.h"
  59. #include "logrecs.h"
  60. #include "logaction.h"
  61. #include "util_funcs.h"
  62. #include "log_intfuncs.h"
  63. #include "log_extfuncs.h"
  64. #include "recover_intfuncs.h"
  65. #include "recover_extfuncs.h"
  66. #include "trans_extfuncs.h"
  67. #include "thread_globals.h"
  68. #include "trans_globals.h"
  69. #include "log_globals.h"
  70. #include "io_globals.h"
  71. #include "bf_globals.h"
  72. #include "recover_globals.h"
  73. #include "distr.h"
  74. #include "distr_globals.h"
  75.  
  76. /* 
  77.  *  counter of number a dirty page table entries received from
  78.  *    LOG_ACTION_CKPNT_DIRTY_PAGES records.
  79.  */
  80. static int    checkPointDPTCount;
  81.  
  82.  
  83.  void
  84. analyzeCheckpoint (
  85.  
  86.     register LOGRECORDHDR        *record,
  87.     register LSNOFFSET            recordLSN 
  88. )
  89. {
  90.     
  91.     register CHECKPOINTINFO        *checkInfo;
  92.     register CHECKTRANS            *checkTrans;
  93.     register TRANSREC            *transRec;
  94.     register int                i;
  95.     register DIRTYPAGEINFO        *tempDirty;
  96.     register DIRTYPAGEINFO        *currentDirty;
  97.     VOLIDNAME                    *mountedVolume;
  98.     CHECKPOINTDPTINFO            *dirtyPageInfoRecord;
  99.  
  100.     TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("recordLSN:%d", recordLSN));
  101.  
  102.     /*
  103.      *    If checkpoint record has already been anaylzed, then
  104.      *    do not analyze any more.  It is possible to not start
  105.      *    at the very latest checkpoint record because the record
  106.      *    may be written, but the log volume's checkpoint info
  107.      *    may not have made it to disk.  This is ok, since starting
  108.      *    at any checkpoint is correct.
  109.      */
  110.     if (AnalyzedCheckpoint == TRUE)    {
  111.  
  112.         TRPRINT(TR_RECOVER|TR_LOG, TR_LEVEL_2, ("not last checkPoint"));
  113.         return;
  114.     }
  115.  
  116.     /*
  117.      *    check to make sure the magics are ok
  118.      */
  119.     SM_ASSERT(LEVEL_2, record->magic == LOGRECORD_MAGIC);
  120.  
  121.     /*
  122.      *    If this is a DirtyPageTable record, update the dirty
  123.      *    page table.
  124.      */
  125.     if (record->action == LOG_ACTION_CKPNT_DIRTY_PAGES) {
  126.         TRPRINT(TR_RECOVER|TR_LOG, TR_LEVEL_2, ("checkpnt DPT record"));
  127.  
  128.         dirtyPageInfoRecord = (CHECKPOINTDPTINFO *) GET_LOG_IMAGE(record, 0);
  129.  
  130.         /* see if this is the first DPT record */
  131.         if (dirtyPageInfoRecord->recordNum == 0) {
  132.             checkPointDPTCount = dirtyPageInfoRecord->numDirtyPages;
  133.         } else {
  134.             checkPointDPTCount += dirtyPageInfoRecord->numDirtyPages;
  135.         }
  136.  
  137.         /*
  138.          *    get a pointer to the dirty page information
  139.          */
  140.         currentDirty = (DIRTYPAGEINFO *) GET_LOG_IMAGE(record, 1);
  141.  
  142.         /*
  143.          *    process the list of dirty pages 
  144.          */
  145.         for (i = 0; i < dirtyPageInfoRecord->numDirtyPages; i++, currentDirty++)    {
  146.  
  147.             TRACE(TR_LOG|TR_RECOVER, TR_LEVEL_2);
  148. #ifdef DEBUG
  149.             SM_ASSERT(LEVEL_3, currentDirty->lrc.count < OpenLog.fileBytes + 1000);
  150.             SM_ASSERT(LEVEL_3, currentDirty->lrc.wrapCount <= OpenLog.wrapCount);
  151.             SM_ASSERT(LEVEL_3, currentDirty->lsn.wrapCount <= OpenLog.wrapCount);
  152.             SM_ASSERT(LEVEL_3, currentDirty->lsn.offset < OpenLog.fileBytes);
  153. #endif DEBUG
  154.  
  155.             /*
  156.              *    check to see if there is a dirty page record
  157.              */
  158.             if ((tempDirty = searchDirtyPageTable( &(currentDirty->pid) )) == NULL)    {
  159.  
  160.                 TRPRINT(TR_RECOVER, TR_LEVEL_2, ("pid not found"));
  161.  
  162.                 /*
  163.                  *    Add the page to the dirty page table
  164.                  */
  165.                 if ((tempDirty = insertDirtyPageTable(&(currentDirty->pid))) == NULL)  {
  166.  
  167.                     SM_ERROR(TYPE_FATAL, esmINTERNAL);
  168.                 }
  169.  
  170.                 /*
  171.                  *    fill in the information
  172.                  */
  173.                 tempDirty->lsn = currentDirty->lsn;
  174.                 tempDirty->lrc = currentDirty->lrc;
  175.                 TRPRINT(TR_RECOVER|TR_LOG, TR_LEVEL_2, ("lsn:%d, lrc:%d", tempDirty->lsn.offset, tempDirty->lrc.count));
  176.  
  177.             } else {
  178.  
  179.                 /*
  180.                  *    The page should not already be in the table, 
  181.                  *    unless more than one checkpoint record is scanned.
  182.                  */
  183.                 SM_ERROR(TYPE_LOG, esmINTERNAL);
  184.             }
  185.         }
  186.  
  187.         return;
  188.     }
  189.  
  190.     /*
  191.      *    get a pointer to the body
  192.      */
  193.     checkInfo = (CHECKPOINTINFO *) GET_LOG_IMAGE(record, 0);
  194.  
  195. #ifdef DEBUG
  196.     {
  197.         int x = (int) checkInfo->numActiveTrans;
  198.         /*
  199.          *    check to make sure the active transactions are ok
  200.          */
  201.         SM_ASSERT(LEVEL_2, (x >= 0));
  202.     }
  203. #endif DEBUG
  204.  
  205.     /* 
  206.      *    Make sure all dirty page table information was recieved
  207.      */
  208.     SM_ASSERT(LEVEL_2, checkPointDPTCount == checkInfo->numDirtyPages);
  209.     
  210.     /*
  211.      *    Check to see if there are any active transactions
  212.      *
  213.      *    There can be no active if this is the initial checkpoint
  214.      */
  215.     if (checkInfo->numActiveTrans > 0)    {
  216.  
  217.         TRPRINT(TR_RECOVER, TR_LEVEL_2, ("numActiveTrans:%d", checkInfo->numActiveTrans));
  218.  
  219.         /*
  220.          *    get a pointer to the transaction information
  221.          */
  222.         checkTrans = (CHECKTRANS *) GET_LOG_IMAGE(record, 1);
  223.  
  224.         /*
  225.          *    process the active transactions
  226.          */
  227.         for (i = 0; i < checkInfo->numActiveTrans; i++, checkTrans++)    {
  228.  
  229.             TRACE(TR_LOG|TR_RECOVER, TR_LEVEL_2);
  230.  
  231.             /*
  232.              * add the trans to the active list only if it really was
  233.              * active at the time of the checkpoint.  An example of one
  234.              * that is NOT active is one that was commited but whose
  235.              * resources had not yet been released at the time the
  236.              * checkpoint was taken
  237.              */
  238.  
  239.             if (TRANS_NOT_ALIVE_AT_CHECKPOINT(checkTrans))
  240.                 continue;
  241.  
  242.  
  243.             /*
  244.              *    check to see if there is a transaction record
  245.              */
  246.             if ((transRec = findTransRec(checkTrans->tid)) == NULL)    {
  247.  
  248.                 TRPRINT(TR_RECOVER, TR_LEVEL_2, ("tid not found"));
  249.  
  250.                 /*
  251.                  *    allocate a transaction record
  252.                  */
  253.                 if ((transRec = allocRecoveryTrans()) == NULL)    {
  254.  
  255.                     SM_ERROR(TYPE_FATAL, esmINTERNAL);
  256.                 }
  257.  
  258.                 /*
  259.                  *    hang the transaction off the hash table
  260.                  */
  261.                 listPush( &(TransHashTable[HASH_TID(checkTrans->tid)]), &(transRec->tidList) );
  262.  
  263.                 /*
  264.                  *    fill in the transaction information
  265.                  */
  266.                 transRec->tid = checkTrans->tid;
  267.                 transRec->firstLSN = checkTrans->firstLSN;
  268.                 transRec->lastLSN = checkTrans->lastLSN;
  269.                 transRec->nextUndoLSN = checkTrans->nextUndoLSN;
  270.  
  271.                 /*
  272.                  *    for distr trans
  273.                  */
  274.                 transRec->transState = checkTrans->state;
  275.                 transRec->numServers = checkTrans->numServers;
  276.                 transRec->prepareLSN = checkTrans->prepareLSN;
  277.  
  278.                 if (transRec->transState == T_ACTIVE) {
  279.                     /*
  280.                      *    change the state to T_RECOVER since that
  281.                      *    corresponds to T_ACTIVE in the checkpoint
  282.                      */
  283.                      transRec->transState = T_RECOVER;
  284.                 }
  285.  
  286.                 /*
  287.                  *    see if the transaction is a distr trans
  288.                  */
  289.                 if ((transRec->transState == T_PREPARED) && 
  290.                     (transRec->numServers == 0)) {
  291.  
  292.                     /*
  293.                      *  add this transRec to list of distr trans
  294.                      *    for which this server is a participant
  295.                      */
  296.                     listEnq( &(ServerDistrTransList), &(transRec->distrTransList) );
  297.                     /*
  298.                      *  increment the number of active distr trans
  299.                      *    for which this server is a participant
  300.                      */
  301.                     numActiveServerDistrTrans++;
  302.                 }
  303.                 else if (((transRec->transState == T_PREPARED) || 
  304.                           (transRec->transState == T_COMMIT)) &&
  305.                          (transRec->numServers > 0)) {
  306.  
  307.                     /*
  308.                      *  add this transRec to list of distr trans
  309.                      *    for which this server is the coordinator
  310.                      */
  311.                     listEnq( &(CoordDistrTransList), &(transRec->distrTransList) );
  312.                     /*
  313.                      *  increment the number of active distr trans
  314.                      *    for which this server is the coordinator
  315.                      */
  316.                     numActiveCoordDistrTrans++;
  317.  
  318.                 } 
  319.  
  320.                 TRPRINT(TR_RECOVER|TR_LOG, TR_LEVEL_2,
  321.                         ("firstLSN:%d lastLSN:%d", transRec->firstLSN.offset, transRec->lastLSN));
  322.             }
  323.         }
  324.     }
  325.  
  326.     /*
  327.      *    check the validity of the checkpoint info
  328.      *    make sure dirty page table is empty (ie. list is empty)
  329.      */
  330.     SM_ASSERT(LEVEL_2, checkInfo->numDirtyPages >= 0);
  331.  
  332.     TRPRINT(TR_RECOVER, TR_LEVEL_2, ("numDirtyPages:%d", checkInfo->numDirtyPages));
  333.  
  334.     /*
  335.      *    Check to see if there are any mounted volumes 
  336.      *    There can be no active if this is the initial checkpoint
  337.      */
  338.     CheckpointVolumeCount = checkInfo->mountedVolCount;
  339.     if (checkInfo->mountedVolCount > 0)    {
  340.  
  341.         /*
  342.          *    get a pointer to the mounted volume information
  343.          */
  344.         mountedVolume = (VOLIDNAME *) GET_LOG_IMAGE(record, 2);
  345.  
  346.         if (checkInfo->mountedVolCount > NumVolumes) {
  347.             fprintf(sm_ErrorStream,
  348.                 "The server's configuration at recovery must match");
  349.             fprintf(sm_ErrorStream,
  350.                 " its configuration at the time of the crash.\n");
  351.             fprintf(sm_ErrorStream,
  352.                 "At the time of the crash, %d volumes were mounted\n",
  353.                     checkInfo->mountedVolCount);
  354.             fprintf(sm_ErrorStream,
  355.                 "The configuration now mounts only %d volumes\n", NumVolumes);
  356.             SM_ERROR(TYPE_STOP, esmCANNOTRECOVER);
  357.         }
  358.  
  359.         /*
  360.          *    process the list of mounted volumes 
  361.          */
  362.         for (i = 0; i < checkInfo->mountedVolCount; i++, mountedVolume++)    {
  363.  
  364.             /*
  365.              *    Add the volume to the checkpoint mounted volume list
  366.              */
  367.             CheckpointVolumes[i] = *mountedVolume;
  368.         }
  369.     }
  370.  
  371.  
  372.     /* we have completed analysis of the checkpoint record */
  373.     AnalyzedCheckpoint = TRUE;
  374.  
  375. }
  376.